package converter;

import org.jdom.output.*;
import org.jdom.*;

import java.io.*;


public class violetSequenceDiagramCreator {

	private Element root;
	private Element top;
	/*
	 * The xml tree is created using JDOM.  The tags and values inside of the tags in the xml file were reverse
	 * engineered from the sample violet sequence diagrams created.  After analyzing the xml scripts and determining
	 * blocks of xml pertaining to the building blocks of the sequence diagram, the methods defined in this class were
	 * then devised.  The four major building blocks pertaining to the sequence diagram were determined to be as follows
	 * the nodes which represented the lifelinenode, the sender activation bar, the receiver activation bar and the 
	 * message.  The activation bars are defined and belong to an existing lifelinenode.  The message requires the 
	 * knowledge of what the sender and receiver activation bars are.  All of the objects defined have names for example
	 * a lifelinenode is given a name of LifelineNode0, LifelineNode1, etc.  The same naming scheme is also used for 
	 * activation bar nodes.  Using JDOM to create the xml tree made life much easier.  The methods defined in this class
	 * are all invoked from the ConversionManager class.
	 */
	public violetSequenceDiagramCreator()
	{
		top = new Element("java");
		top.setAttribute("version", "1.6.0_04");
		top.setAttribute("class", "java.beans.XMLDecoder");		
		root = new Element("object");
		root.setAttribute("class", "com.horstmann.violet.SequenceDiagramGraph");

	}
	/*
	 * The method addNode represents the lifelinenode in the violet uml diagram.  the position of the node is 
	 * systematically calculated.  
	 */
	public void addNode(String name,int i)
	{
		Element aNode = new Element("void");
		aNode.setAttribute("method","addNode");
		
		Element lifeLineNodeObject = new Element("object");
		lifeLineNodeObject.setAttribute("id","LifelineNode"+i);
		lifeLineNodeObject.setAttribute("class","com.horstmann.violet.ImplicitParameterNode");
		
		Element propertyName = new Element("void");
		propertyName.setAttribute("property","name");
		
		Element propertyText = new Element("void");
		propertyText.setAttribute("property","text");

		Element agentName = new Element("string");
		agentName.setText(name);
				
		propertyText.addContent(agentName);
		propertyName.addContent(propertyText);
		lifeLineNodeObject.addContent(propertyName);
		aNode.addContent(lifeLineNodeObject);
		
		Element locationObject = new Element("object");
		locationObject.setAttribute("class","java.awt.geom.Point2D$Double");
		
		Element setLocation = new Element("void");
		setLocation.setAttribute("method","setLocation");
		
		Element yCoord = new Element("double");
		yCoord.setText(String.valueOf((i*200)+ 25));
		Element xCoord = new Element("double");
		xCoord.setText(String.valueOf(0.0));
		setLocation.addContent(yCoord);
		setLocation.addContent(xCoord);
		
		locationObject.addContent(setLocation);
		aNode.addContent(locationObject);
		
		root.addContent(aNode);
	}
		
/*
 * The Method addParentActivationBar represents the sender of the message.  The location of the activation bar is 
 * systematically calculated using the messageNumber 
 */
	public void addParentActivationBar(int messageNumber,int receivingAgentNumber, int sendingAgentNumber)
	{
		
		Element aNode = new Element("void");
		aNode.setAttribute("method","addNode");
		
		Element parentObject = new Element("object");
		parentObject.setAttribute("id","ActivationBarNode"+((2*messageNumber)-2));
		parentObject.setAttribute("class","com.horstmann.violet.CallNode");
		
		Element anotherNode = new Element("void");	
		anotherNode.setAttribute("method","addChild");
		
		Element childObject = new Element("object");
		childObject.setAttribute("id","ActivationBarNode"+((2*messageNumber)-1));
		childObject.setAttribute("class","com.horstmann.violet.CallNode"); 
		 
		Element receivingNode = new Element("void");
		receivingNode.setAttribute("property","implicitParameter");
		
		Element receivingNodeID = new Element("object");
		receivingNodeID.setAttribute("idref","LifelineNode"+receivingAgentNumber);
		
		receivingNode.addContent(receivingNodeID);
		childObject.addContent(receivingNode);
		anotherNode.addContent(childObject);
		parentObject.addContent(anotherNode);
		
		Element sendingNode = new Element("void");
		sendingNode.setAttribute("property","implicitParameter");
		
		Element sendingNodeID = new Element("object");
		sendingNodeID.setAttribute("idref","LifelineNode"+sendingAgentNumber);
		
		sendingNode.addContent(sendingNodeID);
		parentObject.addContent(sendingNode);
		aNode.addContent(parentObject);
		
		Element locationObject = new Element("object");
		locationObject.setAttribute("class","java.awt.geom.Point2D$Double");
		
		Element setLocation = new Element("void");
		setLocation.setAttribute("method","setLocation");
				
		Element xCoord = new Element("double");
		xCoord.setText(String.valueOf((200*sendingAgentNumber)+57));
		
		Element yCoord = new Element("double");
		yCoord.setText(String.valueOf((64*messageNumber)+16));
		
		setLocation.addContent(xCoord);
		setLocation.addContent(yCoord);
		
		locationObject.addContent(setLocation);
		
		aNode.addContent(locationObject);
		
		root.addContent(aNode);	
	}

	/*
	 * The method addChildActivationBar represents the receiver of the message.  Not as many administration details
	 * go into the child activation bar as the parent activation bar 
	 */
	public void addChildActivationBar(int messageNumber,int receivingAgentNumber, int sendingAgentNumber)
	{
		Element aNode = new Element("void");
		aNode.setAttribute("method","addNode");
		
		Element owner = new Element("object");
		owner.setAttribute("idref","ActivationBarNode"+((2*messageNumber)-1));
		
		aNode.addContent(owner);
		
		Element barLocation = new Element("object");
		barLocation.setAttribute("class","java.awt.geom.Point2D$Double");
		
		Element setLocation = new Element("void");
		setLocation.setAttribute("method","setLocation");
		
		Element xCoord = new Element("double");
		xCoord.setText(String.valueOf((200*sendingAgentNumber)+ 57));
		
		Element yCoord = new Element("double");
		yCoord.setText(String.valueOf((64*messageNumber)+ 40));
		
		setLocation.addContent(xCoord);
		setLocation.addContent(yCoord);
		
		barLocation.addContent(setLocation);
		
		aNode.addContent(barLocation);
		
		root.addContent(aNode);					
	}
	
	
	// Violet has two types of messages regular messages and return messages and messageType holds 
	// the type. Passed to this function would be messageType = "com.horstmann.violet.CallEdge" for regular edge
	// and messageType = "com.horstmann.violet.ReturnEdge" the difference is return message is a dashed line.
	// Parent and child refer to the activationNodes created above so
	// an example would be "ActivationBarNode0", "ActivationBarNode1", etc.
	/*
	 * Method addConnection connects two activate bar nodes which actually connects two lifeline nodes together with a 
	 * message.  It was assumed for the purpose of the project that multiagent systems only send asynchronous messages 
	 * which do not have a return value.
	 */
	public void addConnection(String message, int messageNumber)
	{
		Element aNode = new Element("void");
		aNode.setAttribute("method","connect");
		
		Element messageObject = new Element("object");
		messageObject.setAttribute("class","com.horstmann.violet.CallEdge");
		
		Element labelPosition = new Element("void");
		labelPosition.setAttribute("property","middleLabel");
				
		Element messageText = new Element("string");
		messageText.setText(message);
				
		labelPosition.addContent(messageText);
		messageObject.addContent(labelPosition);

		Element messageProperty = new Element("void");
		messageProperty.setAttribute("property","signal");
				
		// boolean = true means open headed arrow
		// boolean  = false means closed headed arrow
		Element arrowHead = new Element("boolean");
		arrowHead.setText("true");
				
		messageProperty.addContent(arrowHead);
		messageObject.addContent(messageProperty);

		
		aNode.addContent(messageObject);
		
		Element sender = new Element("object");
		sender.setAttribute("idref","ActivationBarNode"+((2*messageNumber)-2));
		
		aNode.addContent(sender);
		
		Element receiver = new Element("object");
		receiver.setAttribute("idref","ActivationBarNode"+((2*messageNumber)-1));
		
		aNode.addContent(receiver);
		
		root.addContent(aNode);
	}
	/*
	 * The method below handles writing the xml tree structure to both the specified output file
	 * and to the console.  JDom allows for various ways of formatting the output, the best choice
	 * is to have it done in a prettyFormat which allows the user to see the proper indentation.
	 *   
	 */
//	public File createSequenceDiagram(String fileName)
	public void createSequenceDiagram(String fileName)
	{
		top.addContent(root);

		File outputFile = new File(fileName);
		Document doc = new Document(top);
		XMLOutputter outputter = new XMLOutputter();
		outputter.setFormat(Format.getPrettyFormat());
		    try {
		    	FileWriter fs = new FileWriter(outputFile);
		    	outputter.output(doc, System.out);
		    	outputter.output(doc, fs);
		    }
		    catch (IOException e) {
		      System.err.println(e);
		    }
		    
//		return outputFile;
	}
}